<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=9"/>
<meta name="generator" content="Doxygen 1.8.17"/>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<title>My Project: MQ metrics for Prometheus</title>
<link href="tabs.css" rel="stylesheet" type="text/css"/>
<script type="text/javascript" src="jquery.js"></script>
<script type="text/javascript" src="dynsections.js"></script>
<link href="search/search.css" rel="stylesheet" type="text/css"/>
<script type="text/javascript" src="search/search.js"></script>
<link rel="search" href="search_opensearch.php?v=opensearch.xml" type="application/opensearchdescription+xml" title="My Project"/>
<link href="doxygen.css" rel="stylesheet" type="text/css" />
</head>
<body>
<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
<div id="titlearea">
<table cellspacing="0" cellpadding="0">
 <tbody>
 <tr style="height: 56px;">
  <td id="projectalign" style="padding-left: 0.5em;">
   <div id="projectname">My Project
   </div>
  </td>
 </tr>
 </tbody>
</table>
</div>
<!-- end header part -->
<!-- Generated by Doxygen 1.8.17 -->
<script type="text/javascript">
/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
var searchBox = new SearchBox("searchBox", "search",false,'Search');
/* @license-end */
</script>
<script type="text/javascript" src="menudata.js"></script>
<script type="text/javascript" src="menu.js"></script>
<script type="text/javascript">
/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
$(function() {
  initMenu('',true,true,'search.html','Search');
/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
  $(document).ready(function() {
    if ($('.searchresults').length > 0) { searchBox.DOMSearchField().focus(); }
  });
});
/* @license-end */</script>
<div id="main-nav"></div>
</div><!-- top -->
<div class="PageDoc"><div class="header">
  <div class="headertitle">
<div class="title">MQ metrics for Prometheus </div>  </div>
</div><!--header-->
<div class="contents">
<div class="textblock"><p><a href="https://github.com/agebhar1/mq_exporter/actions/workflows/push.yml"><object type="image/svg+xml" data="https://github.com/agebhar1/mq_exporter/actions/workflows/push.yml/badge.svg" style="pointer-events: none;">CI</object></a> <a href="https://goreportcard.com/report/github.com/agebhar1/mq_exporter"><img src="https://goreportcard.com/badge/github.com/agebhar1/mq_exporter" alt="Go Report Card" class="inline"/></a></p>
<p>Prometheus exporter for <a href="https://www.ibm.com/products/mq">IBM MQ</a>.</p>
<p>The container image is available on Red Hat's <a href="https://quay.io/repository/agebhar1/mq_exporter">quay.io</a> container registry. See <a href="#container">Container</a> section for more details.</p>
<h1><a class="anchor" id="autotoc_md1"></a>
Description</h1>
<p>This exporter is for use in a restricted environment where it's no possible to run <a href="https://www.ibm.com/docs/en/ibm-mq/9.2?topic=reference-programmable-command-formats-pcfs">Programmable command formats (PCFs)</a> and no other services exists such as <a href="https://www.ibm.com/docs/en/ibm-mq/9.2?topic=mq-messaging-using-rest-api">REST</a>.</p>
<p>To use the exporter only the <code>inquire</code> permission for the given queues are required to execute <a href="https://www.ibm.com/docs/en/ibm-mq/9.2?topic=calls-mqinq-inquire-object-attributes">MQINQ</a>.</p>
<p>More or less only the metrics of current queue depth <code>MQIA_CURRENT_Q_DEPTH</code> and maximum queue size <code>MQIA_MAX_Q_DEPTH</code> are (currently) supported as effect of not using PCFs. To run the exporter you need the IB MQ client library for C. The exporter itself is written in <a href="https://go.dev/">Go</a> and uses IBMs <a href="https://github.com/ibm-messaging/mq-golang">mq-golang</a> library, a Go binding to the C client library.</p>
<h2><a class="anchor" id="autotoc_md2"></a>
Metrics</h2>
<table class="markdownTable">
<tr class="markdownTableHead">
<th class="markdownTableHeadNone">Metric </th><th class="markdownTableHeadNone">Type </th><th class="markdownTableHeadNone"><a href="https://www.ibm.com/docs/en/ibm-mq/9.2?topic=calls-mqinq-inquire-object-attributes">MQINQ attribute selector</a> </th><th class="markdownTableHeadNone">Description  </th></tr>
<tr class="markdownTableRowOdd">
<td class="markdownTableBodyNone"><code>mq_queue_current_depth</code> </td><td class="markdownTableBodyNone">gauge </td><td class="markdownTableBodyNone">MQIA_CURRENT_Q_DEPTH </td><td class="markdownTableBodyNone">Number of messages on queue  </td></tr>
<tr class="markdownTableRowEven">
<td class="markdownTableBodyNone"><code>mq_queue_max_depth</code> </td><td class="markdownTableBodyNone">gauge </td><td class="markdownTableBodyNone">MQIA_MAX_Q_DEPTH </td><td class="markdownTableBodyNone">Maximum number of messages allowed on queue  </td></tr>
<tr class="markdownTableRowOdd">
<td class="markdownTableBodyNone"><code>mq_queue_open_input_count</code> </td><td class="markdownTableBodyNone">gauge </td><td class="markdownTableBodyNone">MQIA_OPEN_INPUT_COUNT </td><td class="markdownTableBodyNone">Number of <code>MQOPEN</code> calls that have the queue open for input  </td></tr>
<tr class="markdownTableRowEven">
<td class="markdownTableBodyNone"><code>mq_queue_open_output_count</code> </td><td class="markdownTableBodyNone">gauge </td><td class="markdownTableBodyNone">MQIA_OPEN_OUTPUT_COUNT </td><td class="markdownTableBodyNone">Number of <code>MQOPEN</code> calls that have the queue open  </td></tr>
<tr class="markdownTableRowOdd">
<td class="markdownTableBodyNone"><code>mq_queue_request_duration_seconds</code> </td><td class="markdownTableBodyNone">gauge </td><td class="markdownTableBodyNone">- </td><td class="markdownTableBodyNone">Response time of <code>MQINQ</code> in seconds  </td></tr>
<tr class="markdownTableRowEven">
<td class="markdownTableBodyNone"><code>mq_queue_up</code> </td><td class="markdownTableBodyNone">gauge </td><td class="markdownTableBodyNone">- </td><td class="markdownTableBodyNone"><code>1</code> if <code>MQINQ</code> was successful and within timeout, <code>0</code> otherwise  </td></tr>
</table>
<p>Each metric contains the labels <code>channel</code>, <code>connection</code>, (queue) <code>name</code> and <code>queue_manager</code>.</p>
<p>Beside the above metrics, metrics for Go runtime is also provided by Prometheus go client collector.</p>
<h2><a class="anchor" id="autotoc_md3"></a>
Links</h2>
<ul>
<li><a href="https://www.ibm.com/docs/en/ibm-mq/9.2?topic=windows-authorizations-pcf-commands">Authorizations for PCF commands</a></li>
<li><a href="https://developer.ibm.com/tutorials/mq-develop-mq-rest-api/">Get started with the IBM MQ messaging REST API</a></li>
</ul>
<h2><a class="anchor" id="autotoc_md4"></a>
Alternatives/Products</h2>
<ul>
<li><a href="https://github.com/Appdynamics/websphere-mq-monitoring-extension">https://github.com/Appdynamics/websphere-mq-monitoring-extension</a></li>
<li><a href="https://github.com/Cinimex/mq-java-exporter">https://github.com/Cinimex/mq-java-exporter</a></li>
<li><a href="https://github.com/ibm-messaging/mq-metric-samples">https://github.com/ibm-messaging/mq-metric-samples</a></li>
</ul>
<h1><a class="anchor" id="autotoc_md5"></a>
Usage</h1>
<h1><a class="anchor" id="autotoc_md6"></a>
Configuration</h1>
<div class="fragment"><div class="line">usage: mq_exporter --config=CONFIG [&lt;flags&gt;]</div>
<div class="line"> </div>
<div class="line">A Prometheus exporter for MQ metrics.</div>
<div class="line"> </div>
<div class="line">Flags:</div>
<div class="line">  -h, --help                Show context-sensitive help (also try --help-long and --help-man).</div>
<div class="line">      --config=CONFIG       Path to config yaml file for MQ connections.</div>
<div class="line">      --web.systemd-socket  Use systemd socket activation listeners instead of port listeners (Linux only).</div>
<div class="line">      --web.listen-address=:9873 ...</div>
<div class="line">                            Addresses on which to expose metrics and web interface. Repeatable for multiple addresses.</div>
<div class="line">      --web.config.file=&quot;&quot;  [EXPERIMENTAL] Path to configuration file that can enable TLS or authentication.</div>
<div class="line">      --web.telemetry-path=&quot;/metrics&quot;  </div>
<div class="line">                            Path under which to expose metrics.</div>
<div class="line">  -v, --version             Show application version.</div>
<div class="line">      --log.level=info      Only log messages with the given severity or above. One of: [debug, info, warn, error]</div>
<div class="line">      --log.format=logfmt   Output format of log messages. One of: [logfmt, json]</div>
</div><!-- fragment --><h2><a class="anchor" id="autotoc_md7"></a>
Queue configuration</h2>
<p>The queue configuration file is passed by <code>--config</code> and is required. It's a YAML with these attributes:</p>
<table class="markdownTable">
<tr class="markdownTableHead">
<th class="markdownTableHeadNone">Attribute </th><th class="markdownTableHeadCenter">Required </th><th class="markdownTableHeadNone">Description  </th></tr>
<tr class="markdownTableRowOdd">
<td class="markdownTableBodyNone"><code>queueManager</code> </td><td class="markdownTableBodyCenter">✓ </td><td class="markdownTableBodyNone">name of the queue manager  </td></tr>
<tr class="markdownTableRowEven">
<td class="markdownTableBodyNone"><code>user</code> † </td><td class="markdownTableBodyCenter"></td><td class="markdownTableBodyNone">username for channel authentication  </td></tr>
<tr class="markdownTableRowOdd">
<td class="markdownTableBodyNone"><code>password</code> † </td><td class="markdownTableBodyCenter"></td><td class="markdownTableBodyNone">password for channel authentication  </td></tr>
<tr class="markdownTableRowEven">
<td class="markdownTableBodyNone"><code>connName</code> </td><td class="markdownTableBodyCenter">✓ </td><td class="markdownTableBodyNone">host and port of MQ server  </td></tr>
<tr class="markdownTableRowOdd">
<td class="markdownTableBodyNone"><code>channel</code> </td><td class="markdownTableBodyCenter">✓ </td><td class="markdownTableBodyNone">channel to connect to queues  </td></tr>
<tr class="markdownTableRowEven">
<td class="markdownTableBodyNone"><code>sslCipherSpec</code> ‡ </td><td class="markdownTableBodyCenter"></td><td class="markdownTableBodyNone"><a href="https://www.ibm.com/docs/en/ibm-mq/9.2?topic=fields-sslcipherspec-mqchar32">Cipher Spec</a> which is used for TLS  </td></tr>
<tr class="markdownTableRowOdd">
<td class="markdownTableBodyNone"><code>keyRepository</code> ‡ </td><td class="markdownTableBodyCenter"></td><td class="markdownTableBodyNone">location of <a href="https://www.ibm.com/docs/en/ibm-mq/9.2?topic=mqsco-keyrepository-mqchar256">key repository</a>  </td></tr>
<tr class="markdownTableRowEven">
<td class="markdownTableBodyNone"><code>timeout</code> </td><td class="markdownTableBodyCenter"></td><td class="markdownTableBodyNone">timeout to inquire <b>all</b> queue metrics  </td></tr>
<tr class="markdownTableRowOdd">
<td class="markdownTableBodyNone"><code>queues</code> </td><td class="markdownTableBodyCenter"></td><td class="markdownTableBodyNone">(string) list of (full) queue names  </td></tr>
</table>
<p>† if <code>user</code> is provided, then <code>password</code> is required and will be used; if <code>user</code> is absent then authentication will not be used <br  />
 ‡ if <code>sslCipherSpec</code> is provided, then <code>keyRepository</code> is required and will be used; <code>sslCipherSpec</code> is absent TLS will not be used for MQ connection</p>
<p>An example for IBMs provided Container <code>icr.io/ibm-messaging/mq:latest</code> with the default <a href="https://github.com/ibm-messaging/mq-container/blob/master/docs/developer-config.md">developer config</a> is: </p><div class="fragment"><div class="line">---</div>
<div class="line">queueManager: QM1</div>
<div class="line">user: admin</div>
<div class="line">password: passw0rd</div>
<div class="line">connName: localhost(1414)</div>
<div class="line">channel: DEV.ADMIN.SVRCONN</div>
<div class="line">queues:</div>
<div class="line">  - DEV.QUEUE.1</div>
<div class="line">  - DEV.QUEUE.2</div>
<div class="line">  - DEV.QUEUE.3</div>
</div><!-- fragment --><p>An example with IBM MQ <a href="https://developer.ibm.com/tutorials/mq-secure-msgs-tls/">encrypted connection</a>: </p><div class="fragment"><div class="line">---</div>
<div class="line">queueManager: QM1</div>
<div class="line">user: app</div>
<div class="line">password: passw0rd</div>
<div class="line">connName: localhost(1414)</div>
<div class="line">channel: DEV.APP.SVRCONN</div>
<div class="line">sslCipherSpec: TLS_RSA_WITH_AES_256_CBC_SHA256</div>
<div class="line">keyRepository: keys/clientkey</div>
<div class="line">queues:</div>
<div class="line">  - DEV.QUEUE.1</div>
<div class="line">  - DEV.QUEUE.2</div>
<div class="line">  - DEV.QUEUE.3</div>
</div><!-- fragment --><p>Run with: </p><div class="fragment"><div class="line">$ mkdir keys &amp;&amp; pushd $_</div>
<div class="line">$ openssl req -newkey rsa:2048 -nodes -keyout key.key -x509 -days 365 -out key.crt</div>
<div class="line">$ chmod g+rw key.key # otherwise it can&#39;t be read w/ podman</div>
<div class="line">$ # openssl x509 -text -noout -in key.crt</div>
<div class="line">$ runmqakm -keydb -create -db clientkey.kdb -pw [!!pick_a_passw0rd_here!!] -type pkcs12 -stash</div>
<div class="line">$ runmqakm -cert -add -label QM1.cert -db clientkey.kdb -stashed -trust enable -file key.crt</div>
<div class="line">$ popd</div>
<div class="line">$ podman run --rm \</div>
<div class="line">    --env LICENSE=accept \</div>
<div class="line">    --env MQ_APP_PASSWORD=passw0rd \</div>
<div class="line">    --env MQ_QMGR_NAME=QM1 \</div>
<div class="line">    --publish 1414:1414 \</div>
<div class="line">    --volume $(pwd)/keys:/etc/mqm/pki/keys/mykey \</div>
<div class="line">    icr.io/ibm-messaging/mq</div>
</div><!-- fragment --><h2><a class="anchor" id="autotoc_md8"></a>
TLS and basic authentication</h2>
<p>The MQ exporter uses Prometheus <a href="https://github.com/prometheus/exporter-toolkit">exporter-toolkit</a> to support TLS and/or basic authentication. You need to pass a configuration file using the <code>--web.config</code> parameter. The file format is described on <a href="https://github.com/prometheus/exporter-toolkit/blob/master/docs/web-configuration.md">web configuration</a>.</p>
<h1><a class="anchor" id="autotoc_md9"></a>
Build</h1>
<p>To build the project the IBM client library is necessary due to the use of the <code>mq-golang</code> package. For development see <a href="https://developer.ibm.com/articles/mq-downloads/">IBM MQ Downloads for developers</a> and choose 'Redist (grab &amp; go) MQ Downloads'. For the sake of simplicity assume the library is located at <code>/opt/mqm</code> otherwise you have to update <code>CGO_CFLAGS</code> and <code>CGO_LDFLAGS</code> appropriate. For more details see <a href="https://github.com/ibm-messaging/mq-golang#using-the-package">using the [mq-golang] package</a>.</p>
<p>The project provides a <code>Makefile</code>. To run all tests and build the exporter call:</p>
<div class="fragment"><div class="line">$ make</div>
</div><!-- fragment --><h2><a class="anchor" id="autotoc_md10"></a>
Binary</h2>
<p>The binary of the <code>mq_exporter</code> will not be available since it's build with C GO and depends on the build time versions of underlying libraries beside of IBM MQ itself.</p>
<h2><a class="anchor" id="autotoc_md11"></a>
Container</h2>
<p>The container image is available on Red Hat's <a href="https://quay.io/repository/agebhar1/mq_exporter">quay.io</a> container registry and does no contain the IBM MQ libraries because of the missing unawareness about the legal guidelines. The containers user is 'nobody' (UID: 65534).</p>
<p>To run the container there are at least two options. Either build your own image like: </p><div class="fragment"><div class="line">FROM quay.io/agebhar1/mq_exporter:&lt;tag&gt;</div>
<div class="line"> </div>
<div class="line">COPY &lt;mqm&gt; /opt/mqm</div>
<div class="line"> </div>
<div class="line">…</div>
</div><!-- fragment --><p>Or by mounting the library on start like: </p><div class="fragment"><div class="line">$ podman run --rm -v $(pwd)/mqm:/opt/mqm -v $(pwd)/config.yml:/etc/mq_exporter/config.yml -p 9873:9873 quay.io/agebhar1/mq_exporter:latest</div>
<div class="line">…</div>
</div><!-- fragment --><p>The configuration file is expect to be <code>/etc/mq_exporter/config.yml</code> which can be mounted too.</p>
<h2><a class="anchor" id="autotoc_md12"></a>
Links</h2>
<ul>
<li><a href="https://github.com/ibm-messaging/mq-golang">https://github.com/ibm-messaging/mq-golang</a></li>
<li><a href="https://developer.ibm.com/articles/mq-downloads">https://developer.ibm.com/articles/mq-downloads</a></li>
<li><a href="https://developer.ibm.com/tutorials/mq-connect-app-queue-manager-containers/">https://developer.ibm.com/tutorials/mq-connect-app-queue-manager-containers/</a></li>
</ul>
<h1><a class="anchor" id="autotoc_md13"></a>
License</h1>
<p>The repository and all contributions are licensed under <a href="https://www.apache.org/licenses/LICENSE-2.0">APACHE 2.0</a>. Please review our [LICENSE](LICENSE) file. </p>
</div></div><!-- contents -->
</div><!-- PageDoc -->
<!-- start footer part -->
<hr class="footer"/><address class="footer"><small>
Generated by &#160;<a href="http://www.doxygen.org/index.html">
<img class="footer" src="doxygen.png" alt="doxygen"/>
</a> 1.8.17
</small></address>
</body>
</html>
